package com.my.study.myvolatile;

import java.util.concurrent.TimeUnit;

/**
 * volatile在单例双重检索模式使用
 * jmm Java内存模型:只是一个概念,不是真实存在,必须保证原子性、可见性、有序性
 * volatile 关键词保证可见性、不保证原子性、禁止指令重排(保证有序性)
 * 禁止指令重排:编译器优化性能,会对Java代码执行顺序进行重排
 */
public class StudyVolatileDemo {

    public static void main(String[] args) {
        //testVolatileNo();
        //testVolatileOk();
        //testAtomicNo();
        testAtomicOk();
    }

    /**
     * 保证原子性
     */
    private static void testAtomicOk() {
        MyData myData = new MyData();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    myData.addAtomicNum();
                    myData.addNum(1);
                }
            }, "AAA").start();
        }
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + " int>>>>>>>>>>>>>>>>>:" + myData.num);
        System.out.println(Thread.currentThread().getName() + " atomicInteger>>>>>>>>>>>>>>>>>:" + myData.atomicInteger);
    }

    /**
     * 不保证原子性
     */
    private static void testAtomicNo() {
        MyData myData = new MyData();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    myData.addNum(1);
                }
            }, "AAA").start();
        }
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + ">>>>>>>>>>>>>>>>>:" + myData.num);
    }

    /**
     * volatile可见性
     */
    private static void testVolatileOk() {
        MyData myData = new MyData();
        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception exception) {
                exception.printStackTrace();
            }
            myData.addNum(60);
            System.out.println(Thread.currentThread().getName() + ">>>>>>>>>>>>>>>>>:" + myData.num);
        }, "AAA").start();
        // main线程读取index的值
        while (myData.num == 0) {
        }
        System.out.println(Thread.currentThread().getName() + ":" + myData.num);
    }

    /**
     * 不可见
     */
    private static void testVolatileNo() {
        MyData myData = new MyData();
        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception exception) {
                exception.printStackTrace();
            }
            myData.addIndex();
            System.out.println(Thread.currentThread().getName() + ">>>>>>>>>>>>>>>>>:" + myData.index);
        }, "AAA").start();
        // main线程读取index的值
        while (myData.index == 0) {
        }
        System.out.println(Thread.currentThread().getName() + ":" + myData.index);
    }
}
